import { BaseError, BaseResp } from "../../../entity/BaseEntity";
import { EnumCode } from "../../../entity/Code";
import { IGlobal } from "../../../entity/Global";
import { PlusRedis } from "../../PlusRedis";
import { SocketClient } from "./SocketClient";
import { WsServer } from "./WsServer";

declare var global: IGlobal;
export abstract class WsBaseService {
    private _methods: { [funcName: string]: RegistMethodVo };
    protected _linkId: string;
    protected _client: SocketClient;
    private _parent: WsServer;
    constructor(linkId: string, parent: WsServer) {
        this._methods = {};
        this._linkId = linkId;
        this._parent = parent;
        this.mInitFuns();
    }

    protected abstract mInitFuns();


    protected _regist(func: Function) {
        var str = func.toString().split("\r\n")[0];
        var arr;
        if (str.indexOf("(") != -1 && str.indexOf(")") != -1) {
            str = str.split("(")[1].split(")")[0];
            str = str.replace(/\s+/g, "");
            arr = str.split(",");
            for (var i = 0; i < arr.length; i++) {
                var dengIndex = arr[i].indexOf("=");
                if (dengIndex != -1) {
                    arr[i] = String(arr[i]).substring(0, dengIndex);
                }
            }
        }
        let methodVo = new RegistMethodVo(this, func, func.name, ...arr);
        this._methods[methodVo.name] = methodVo;
    }

    async execute(funcName: string, cmd: string, data: any, id: number, client: SocketClient) {
        let methodVo = this._methods[funcName];
        this._client = client;
        if (methodVo) {
            if (!this.mAuthentication(funcName, data, client)) return;
            let startT = Date.now();
            var arg = [];
            for (var i = 0; data && methodVo.args && i < methodVo.args.length; i++) {
                arg.push(data[methodVo.args[i]]);
            }
            let response: BaseResp;
            try {
                let result = await methodVo.func.call(methodVo.caller, ...arg);
                if (result) {
                    response = new BaseResp(0, result);
                }
            } catch (err) {
                global.log.error("失败" + cmd + "[" + client.ip + "]----" + (data ? JSON.stringify(data) : "") + "\r\n" + err.stack);
                response = new BaseResp(err.code || EnumCode.FAIL, {}, global.Debug ? err.stack : err.message);
            }
            response && this._parent.sendCmd(this._linkId, cmd, response, id);
            global.log.trace(`执行${cmd}消耗${Date.now() - startT}ms`);
        }
    }

    throwError(message: string, code?: number) {
        throw new BaseError(message, code);
    }

    protected mAuthentication(funcName: string, data: any, client: SocketClient): boolean {
        return true;
    }

    public get log() {
        return global.log;
    }

    get redis() {
        return global.plus.getPlus(PlusRedis).client;
    }
}


export class RegistMethodVo {
    public func: Function;
    public name: string;
    public args: Array<any>;
    public caller: any;
    public uri: string;
    constructor(caller: any, func: Function, name: string, ...args) {
        this.func = func;
        this.name = name;
        this.args = args;
        this.caller = caller;
    }
}